﻿using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Sustainalytics.OAuth.Services.Common;
using Sustainalytics.Utils.Logging.Serilog.Messages;
using Sustainalytics.Utils.Serilog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace Sustainalytics.Accounts.Service.SignalRHub
{
    public class UserLoginHubManager
    {
        private static readonly Lazy<UserLoginHubManager> _lazy = new Lazy<UserLoginHubManager>(() => new UserLoginHubManager());

        private readonly ConcurrentDictionary<string, List<string>> _userConnected;

        private UserLoginHubManager()
        {
            _userConnected = new ConcurrentDictionary<string, List<string>>();
        }

        /// <summary>
        /// Hub clients.
        /// </summary>
        private static IHubConnectionContext<dynamic> Clients
        {
            get
            {
                return GlobalHost.ConnectionManager.GetHubContext<UserLoginHub>().Clients;
            }
        }

        public static UserLoginHubManager Instance
        {
            get { return _lazy.Value; }
        }

        public void AddOrUpdateClients(string userName, string connectionId)
        {
            if (_userConnected.ContainsKey(userName))
            {
                var data = _userConnected[userName] ?? new List<string>();
                if (data.All(c => c != connectionId))
                {
                    data.Add(connectionId);
                }
                _userConnected[userName] = data;
            }
            else
            {
                _userConnected.TryAdd(userName, new List<string>() { connectionId });
            }

            List<string> val;
            if (_userConnected.TryGetValue(userName, out val))
                CommonEventSerilog.Log.Info(AuthServiceMessage.SignalRHubAddOrUpdateClients, userName, connectionId, val.Count);
        }

        public void RemoveClients(string userName, string connectionId)
        {
            if (_userConnected.ContainsKey(userName))
            {
                var data = _userConnected[userName] ?? new List<string>();
                data.Remove(connectionId);
                _userConnected[userName] = data;
            }
            else
            {
                _userConnected.TryAdd(userName, new List<string>());
            }

            List<string> val;
            if (_userConnected.TryGetValue(userName, out val))
                CommonEventSerilog.Log.Info(AuthServiceMessage.SignalRHubRemoveClients, userName, connectionId, val.Count);
        }

        public void NotifyClients(string method)
        {
            CommonEventSerilog.Log.Info(AuthServiceMessage.SignalRHubNotifyClients);
            var connections = _userConnected.Values.SelectMany(a => a).ToList();

            Clients.All.notifyClient(method);

            CommonEventSerilog.Log.Info(AuthServiceMessage.SignalRHubNotifiedClients, (connections != null) ? connections.Count : 0);
        }
    }
}
